<template>
  <div class="flex flex-col h-full">
    <div class="overflow-y-auto p-10 flex-1">
      <MessageList :messages="convsersation!.msgList" ref="messageListRef" />
    </div>
    <div class="w-[80%] mx-auto flex items-center my-5">
      <MessageInput
        ref="dom_MessageInput"
        @create="sendNewMessage"
        v-model="inputValue"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import MessageList from "../components/MessageList.vue";
import MessageInput from "../components/MessageInput.vue";
import dayjs from "dayjs";
import { useRoute } from "vue-router";
import { MessageStatus } from "../types";
import { useConversationStore } from "../stores/conversation";

const dom_MessageInput = ref<{ ref_input: HTMLInputElement }>();
const conversationStore = useConversationStore();

const route = useRoute();

// 从路由中获取会话id
let conversationId = ref(parseInt(route.params.id as string));

// 根据从路由获取的会话id 从 pinia 中筛选出当前会话
const convsersation = computed(() =>
  conversationStore.getConversationById(conversationId.value)
);

watch(
  () => route.params.id,
  async (newId: string) => {
    conversationId.value = parseInt(newId);
    // 切换当前会话时，聊天区自动滚动到底部
    await messageScrollToBottom();
    // 切换当前会话时，将当前会话的消息列表的高度重置为0
    currentMessageListHeight = 0;
  }
);

const sendNewMessage = async (question: string, imagePath?: string) => {
  let copiedImagePath: string | undefined;
  if (imagePath) {
    try {
      copiedImagePath = await window.electronAPI.copyImageToUserDir(imagePath);
    } catch (error) {
      console.error("拷贝图片失败:", error);
    }
  }

  // 获取格式化的当前时间
  let currentTime = dayjs().format("YYYY-MM-DD HH:mm:ss");

  // 向消息列表中追加新的问题
  convsersation.value!.msgList.push({
    type: "question",
    content: question,
    ...(copiedImagePath && { imagePath: copiedImagePath }),
    createdAt: currentTime,
    updatedAt: currentTime,
  });

  // 向消息列表中追加 loading 状态的回答
  let new_msgList_length = convsersation.value!.msgList.push({
    type: "answer",
    content: "",
    createdAt: currentTime,
    updatedAt: currentTime,
    status: "loading",
  });

  // 消息列表的最后一条消息为 loading 状态的回答，其id为消息列表的长度 - 1
  let loading_msg_id = new_msgList_length - 1;

  // 访问 AI 模型获取答案，参数为 loading 状态的消息的id
  get_AI_answer(loading_msg_id);

  // 清空问题输入框
  inputValue.value = "";

  await messageScrollToBottom();

  // 发送问题后，问题输入框自动聚焦
  if (dom_MessageInput.value) {
    dom_MessageInput.value.ref_input.focus();
  }
};

const inputValue = ref("");

onMounted(async () => {
  if (route.query.type === "new") {
    // 新创建的会话需初始化消息，传参为第一个答案的下标 1
    await get_AI_answer(1);
  }

  // 初次加载会话时，清空流式消息的内容
  let streamContent = "";

  // 监听 AI 模型的返回
  window.electronAPI.onUpdateMessage(
    async (streamData: { messageId: any; data: any }) => {
      // 从 AI 的返回中解构出 messageId 和 data
      const { messageId, data } = streamData;

      // AI 的回答为消息流，每次接收到新的流式消息，都将其追加到 streamContent 中
      streamContent += data.result;

      // 函数封装 -- 解析返回值，格式化为消息的状态
      const getMessageStatus = (data: any): MessageStatus => {
        if (data.is_error) {
          return "error";
        } else if (data.is_end) {
          return "finished";
        } else {
          return "streaming";
        }
      };

      // 根据消息id, 获取到 loading 状态的消息
      let msg = convsersation.value!.msgList[messageId];
      // 将 AI 回答的流式消息替换掉 loading 状态的消息
      msg.content = streamContent;
      // 根据 AI 的返回，更新消息的状态
      msg.status = getMessageStatus(data);
      // 用 dayjs 得到格式化的当前时间字符串
      msg.updatedAt = dayjs().format("YYYY-MM-DD HH:mm:ss");

      // 顺滑滚动到底部
      await nextTick();
      await checkAndScrollToBottom();

      // 本次回答结束后
      if (data.is_end) {
        // 清空流式消息的内容
        streamContent = "";

        // 更新会话时，需要移除 id 字段，否则会报错
        let temp_convsersation = JSON.parse(
          JSON.stringify(convsersation.value)
        );
        delete temp_convsersation.id;

        await conversationStore.updateConversation(
          convsersation.value!.id,
          temp_convsersation
        );
      }
    }
  );

  await messageScrollToBottom();
});

let currentMessageListHeight = 0;
const checkAndScrollToBottom = async () => {
  if (messageListRef.value) {
    const newHeight = messageListRef.value.ref.clientHeight;
    if (newHeight > currentMessageListHeight) {
      currentMessageListHeight = newHeight;
      await messageScrollToBottom("smooth");
    }
  }
};

// 访问 AI 模型，获取答案
const get_AI_answer = async (answerIndex: number) => {
  await window.electronAPI.startChat({
    messageId: answerIndex,
    providerName: convsersation.value!.AI_providerName,
    selectedModel: convsersation.value!.AI_modelName,
    // 发给AI模型的消息需移除最后一条加载状态的消息,使最后一条消息为用户的提问
    messages: convsersation
      .value!.msgList.map((message) => ({
        role: message.type === "question" ? "user" : "assistant",
        content: message.content,
        // 若有图片信息，则将其添加到消息中
        ...(message.imagePath && { imagePath: message.imagePath }),
      }))
      .slice(0, -1),
  });
};

const messageListRef = ref<{ ref: HTMLDivElement }>();

const messageScrollToBottom = async (behavior?: string) => {
  await nextTick();
  if (messageListRef.value) {
    // 获取到自定义组件内的真实 ref 调用 scrollIntoView
    messageListRef.value.ref.scrollIntoView({
      block: "end",
      behavior: behavior as ScrollBehavior, // "auto" | "instant" | "smooth"
    });
  }
};

// 待开发：发送问题后，内容顺滑下滚，直到问题抵达顶部时，不再下滚
</script>

<style scoped></style>
